/*
 * Licensed to the 南京汇海交通科技有限公司
 *
 * Copyright (c) 2025.
 * All rights reserved.
 *
 * 本软件属南京汇海交通科技有限公司所有，在未获得南京汇海交通科技有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.chframework.boot.web.support;

import cn.hutool.core.util.IdUtil;
import com.chframework.boot.core.response.status.ApiStatusEnum;
import com.chframework.common.constant.ApplicationConstant;
import com.chframework.common.exception.ApplicationException;
import com.chframework.common.exception.SystemInterrupterException;
import com.chframework.common.thread.threadlocal.TTLRequestContextHolder;
import com.chframework.common.thread.threadlocal.TransmittableThreadLocalHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class WebMvcHelper {

    /**
     * 是否跳过拦截器
     */
    public static boolean skipIntercept(HttpServletRequest request, Object handler) throws ApplicationException {
        try {
            if (request.getRequestURI().startsWith(ApplicationConstant.ERROR_PATH)) {
                return true;
            }
            if (handler instanceof HandlerMethod || handler instanceof ParameterizableViewController) {
                return false;
            }
            // 因为在项目中集成了swagger2，所以此处需要放行
            if (handler instanceof ResourceHttpRequestHandler) {
                return false;
            }
            throw new SystemInterrupterException(ApiStatusEnum.ERR_A0001);
        } catch (Exception e) {
            throw new ApplicationException(e);
        }
    }

    /**
     * 初始化当前HTTP请求线程缓存
     */
    public static void initialThreadCache(HttpServletRequest request, HttpServletResponse response) {
        ConcurrentHashMap<String, String> environment = TransmittableThreadLocalHelper.getEnvironment();
        log.debug("调试目的 - 【{}】 - 当前线程ThreadLocal缓存数据：{} ；当前线程MDC缓存数据：{} ",
                Thread.currentThread().getName(),
                environment,
                MDC.getMDCAdapter().getCopyOfContextMap());
        String requestId = request.getHeader(ApplicationConstant.RESPONSE_IDENTITY);
        if (StringUtils.isEmpty(requestId)) {
            requestId = environment.get(ApplicationConstant.RESPONSE_IDENTITY);
        }
        if (StringUtils.isEmpty(requestId)) {
            requestId = MDC.get(ApplicationConstant.RESPONSE_IDENTITY);
        }
        if (StringUtils.isEmpty(requestId)) {
            requestId = IdUtil.objectId();
        }

        // MDC记录requestId
        MDC.put(ApplicationConstant.RESPONSE_IDENTITY, requestId);

        // 同时给TransmittableThreadLocal记录requestId
        environment.put(ApplicationConstant.RESPONSE_IDENTITY, requestId);

        // 在HTTP请求的响应头中记录requestId
        response.setHeader(ApplicationConstant.RESPONSE_IDENTITY, requestId);

        // 同步MDC的缓存数据到TransmittableThreadLocal中，后续它会在子线程中再次赋值给我
        MDC.getCopyOfContextMap().forEach((k, v) -> {
            if (Objects.nonNull(k) && Objects.nonNull(v)) {
                environment.putIfAbsent(k, v);
            }
        });
        log.debug("调试目的 - 【{}】 - 当前线程HTTP请求的唯一标识 {}={} ；当前线程ThreadLocal缓存数据：{} ；当前线程MDC缓存数据：{} ",
                Thread.currentThread().getName(),
                ApplicationConstant.RESPONSE_IDENTITY, requestId,
                TransmittableThreadLocalHelper.getEnvironment(),
                MDC.getMDCAdapter().getCopyOfContextMap());
    }

    /**
     * 清理当前HTTP请求线程缓存
     */
    public static void clearThreadCache() {
        log.debug("调试目的 - 【{}】 - 开始清除当前线程ThreadLocal缓存数据 和 MDC缓存数据", Thread.currentThread().getName());
        // 清除数据
        MDC.remove(ApplicationConstant.RESPONSE_IDENTITY);
        MDC.clear();
        TransmittableThreadLocalHelper.getEnvironment().clear();
        TransmittableThreadLocalHelper.remove();

        // 清除请求上下文
        TTLRequestContextHolder.clearPoolThreadContext();
    }

}
